﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using iTunesLib;
using System.IO;

namespace iTunesUpdater
{
  public partial class Form1 : Form
  {
    const string transcodeActiveFile = "transcode.txt";

    TimeSpan addInterval = new TimeSpan(0, 10, 0);
    TimeSpan deleteInterval = new TimeSpan(12, 0, 0);
    TimeSpan transcodeInterval = new TimeSpan(0, 10, 0);
    DateTime nextAdd = DateTime.Now;
    DateTime nextDelete = DateTime.Now;
    DateTime nextTranscode = DateTime.Now;

    public Form1() {
      InitializeComponent();
    }

    private void timer1_Tick(object sender, EventArgs e) {
      if (DateTime.Now >= nextAdd && cbAddnew.Checked)
        AddNow();
      if (DateTime.Now >= nextDelete && cbKillDead.Checked)
        KillDeadNow();
      if (DateTime.Now >= nextTranscode && cbTranscode.Checked)
        TranscodeAll();


      TimeSpan ts = new TimeSpan(0);
      if (cbTranscode.Checked)
        ts = nextTranscode - DateTime.Now;
      else if (cbAddnew.Checked)
        ts = nextAdd - DateTime.Now;
      else if (cbKillDead.Checked)
        ts = nextDelete - DateTime.Now;

      lTimer.Text =
        ts.Hours.ToString("00") + ":"
        + ts.Minutes.ToString("00") + ":"
        + ts.Seconds.ToString("00");

    }

    private void bScan_Click(object sender, EventArgs e) {
      if (cbAddnew.Checked) AddNow();
      if (cbKillDead.Checked) KillDeadNow();
      if (cbTranscode.Checked) TranscodeAll();
    }

    private void AddNow() {
      bScan.Enabled = false;
      timer1.Enabled = false;
      AddNewTracks();
      nextAdd = DateTime.Now + addInterval;
      timer1.Enabled = true;
      bScan.Enabled = true;
    }

    private void KillDeadNow() {
      bScan.Enabled = false;
      timer1.Enabled = false;
      RemoveDeadTracks();
      nextDelete = DateTime.Now + deleteInterval;
      timer1.Enabled = true;
      bScan.Enabled = true;
    }

    SortedList<string, string> TrackList = new SortedList<string, string>();
    void ReadTrackList() {
      if (TrackList.Count == 0) {
        RemoveDeadTracks();
      }
    }

    public void RemoveDeadTracks() {
      try {
        TrackList.Clear();
        iTunesLib.iTunesApp iTunes = new iTunesLib.iTunesApp();
        int deletedTracks = 0;

        IITTrackCollection tracks = iTunes.LibraryPlaylist.Tracks;
        int numTracks = tracks.Count;
        progressBar2.Value = 0;
        progressBar2.Maximum = numTracks;

        while (numTracks > 0) {
          iTunesLib.IITTrack currTrack = tracks[numTracks];

          // is this a file track?
          if (currTrack.Kind == iTunesLib.ITTrackKind.ITTrackKindFile) {
            iTunesLib.IITFileOrCDTrack track = (iTunesLib.IITFileOrCDTrack)currTrack;
            // yes, does it have an empty location?
            if (!System.IO.File.Exists(track.Location)) {
              tbLog.AppendText("Removed " + currTrack.Name + "\r\n");
              // yes, delete it
              currTrack.Delete();
              deletedTracks++;
            }
            else if (!TrackList.ContainsKey(track.Location))
              TrackList.Add(track.Location, track.Name);
          }

          numTracks--;
          progressBar2.Value = numTracks;
          lTimer.Text = numTracks.ToString();
          Application.DoEvents();
        }

      }
      catch (Exception ex) {
        MessageBox.Show("Cannot remove dead tracks.\r\n" + ex.Message);
      }

    }

    iTunesLib.IITOperationStatus AddStatus;
    List<string> NewFiles = new List<string>();
    public void AddNewTracks() {
      TitleScanner scanner = new TitleScanner(ucItemList1.Items);
      try {
        iTunesLib.iTunesApp iTunes = new iTunesLib.iTunesApp();

        int i;
        System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(tbDest.Text);
        System.IO.FileInfo[] files = dir.GetFiles("*.mp4", System.IO.SearchOption.AllDirectories);
        iTunesLib.IITLibraryPlaylist mainLibrary = iTunes.LibraryPlaylist;

        progressBar2.Value = 0;
        progressBar2.Maximum = files.Length;

        for (i = 0; i < files.Length; i++) {
          System.IO.FileInfo file = files[i];
          progressBar2.Value = i;
          lTimer.Text = i.ToString() + "/" + files.Length.ToString();
          Application.DoEvents();

          string ext = System.IO.Path.GetExtension(file.FullName).ToLower();
          TrackInfo info = scanner.GetTrackInfo(file.Name);
          IITTrack foundTrack = mainLibrary.Tracks.get_ItemByName(info.Name);
          if (foundTrack == null) {
            tbLog.AppendText("Adding " + file.Name + "...");
            AddStatus = iTunes.LibraryPlaylist.AddFile(file.FullName);
            if (AddStatus != null) {
              iTunesLib.IITFileOrCDTrack track = (iTunesLib.IITFileOrCDTrack)AddStatus.Tracks[1];
              track.VideoKind = ITVideoKind.ITVideoKindTVShow;
              track.Show = info.ShowName;
              track.Name = info.Name;
            }
            tbLog.AppendText("done.\r\n");
          }
        }
        progressBar2.Value = progressBar2.Maximum;
      }
      catch (Exception ex) {
        MessageBox.Show(this, "Can't scan for new files.\r\n" + ex.Message, "Scan Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
      }
    }

    private void Form1_Load(object sender, EventArgs e) {
      tbDest.Text = iTunesUpdater.Properties.Settings.Default.MediaPath;
      tbSource.Text = Properties.Settings.Default.SourcePath;
      nextAdd = DateTime.Now.AddSeconds(30);
      nextDelete = DateTime.Now.AddSeconds(30);
      cbAddnew.Checked = Properties.Settings.Default.AddEnabled;
      cbKillDead.Checked = Properties.Settings.Default.RemoveEnabled;
      cbTranscode.Checked = Properties.Settings.Default.TranscodeEnabled;

      nextTranscode = DateTime.Now.AddMinutes(1);
      nextAdd = DateTime.Now.AddMinutes(2);
      nextDelete = DateTime.Now.AddMinutes(3);

      timer1.Enabled = true;
    }

    private void bSetPath_Click(object sender, EventArgs e) {
      FolderBrowserDialog d = new FolderBrowserDialog();
      try {
        d.SelectedPath = tbDest.Text;
      }
      catch {
      }

      if (d.ShowDialog() == DialogResult.OK)
        tbDest.Text = d.SelectedPath;
    }

    private void Form1_FormClosing(object sender, FormClosingEventArgs e) {
      Properties.Settings.Default.MediaPath = tbDest.Text;
      Properties.Settings.Default.SourcePath = tbSource.Text;
      Properties.Settings.Default.AddEnabled = cbAddnew.Checked;
      Properties.Settings.Default.RemoveEnabled = cbKillDead.Checked;
      Properties.Settings.Default.TranscodeEnabled = cbTranscode.Checked;

      Properties.Settings.Default.Filters.Clear();
      foreach (string filter in ucItemList1.Items) {
        Properties.Settings.Default.Filters.Add(filter);
      }
      Properties.Settings.Default.Save();
    }

    private void ucItemList1_Load(object sender, EventArgs e) {
      ucItemList1.PromptText = "Enter filter definition:"
        + "\r\n<s> - Show Name"
        + "\r\n<e> - Episode"
        + "\r\n<y> - Air Date Year"
        + "\r\n<m> - Air Date Month"
        + "\r\n<d> - Air Date Day"
        + "\r\n<x> - Part Number (the 1 in in 1/2)"
        + "\r\n<n> - Total Parts (the 2 in in 1/2)"
        + "\r\n<f> - File Number (for multi-file videos)";
      ucItemList1.PromptTitle = "Edit Filer Definition";

      ucItemList1.Items.Clear();
      foreach (string filter in Properties.Settings.Default.Filters) {
        ucItemList1.Items.Add(filter);
      }
    }

    private void button1_Click(object sender, EventArgs e) {
      TitleScanner scanner = new TitleScanner(ucItemList1.Items);

      foreach (string path in tbSource.Text.Split(';')) {
        string[] files = System.IO.Directory.GetFiles(path, "*.mpg", System.IO.SearchOption.AllDirectories);
        foreach (string file in files) {
          TrackInfo t = scanner.GetTrackInfo(file);
          tbLog.AppendText(
            "File: " + System.IO.Path.GetFileName(file)
            + "\r\n  Show: " + t.ShowName
            + "\r\n  Episode: " + t.Name
            + "\r\n  Date: " + t.Month + "/" + t.Day + "/" + t.Year
            + "\r\n-----------------------------------------------"
            + "\r\n");
        }
      }

    }

    private void bKill_Click(object sender, EventArgs e) {
      KillDeadNow();
    }

    private void bAddTracks_Click(object sender, EventArgs e) {
      AddNow();
    }

    private void button3_Click(object sender, EventArgs e) {
      FolderBrowserDialog d = new FolderBrowserDialog();
      try {
        d.SelectedPath = tbSource.Text;
      }
      catch {
      }

      if (d.ShowDialog() == DialogResult.OK)
        tbSource.Text = d.SelectedPath;
    }

    private void bTranscode_Click(object sender, EventArgs e) {
      if (isTranscodeActive()) {
        if (MessageBox.Show(null, "A transcode may be in progress. Reset transcode flag?", "Start Transcode", MessageBoxButtons.YesNo) == DialogResult.Yes) {
          SetTranscodeActive("");
        }
      }
      TranscodeAll();
    }

    void TranscodeAll() {
      foreach (string folder in tbSource.Text.Split(';')) {
        // do not transcode if the transcoder is running.
        if (isTranscodeActive())
          break;
        TranscodeFolder(folder);
      }
      nextTranscode = DateTime.Now + transcodeInterval;
    }

    public void TranscodeFolder(string Folder) {
      System.Diagnostics.Debug.WriteLine("Folder " + Folder);
      string[] files = System.IO.Directory.GetFiles(Folder, "*.mpg", System.IO.SearchOption.AllDirectories);

      // we're only going to transcode one file. So when we find the first file with the archive bit set, 
      // start the transcoder.
      foreach (string file in files) {
        FileInfo fi = new System.IO.FileInfo(file);
        FileAttributes fa = fi.Attributes;
        // if the archive bit is set, but it's not hidden, transcode it.
        // BTV hides files that are actively being recorded (convenient, eh?) 
        if (((fa & FileAttributes.Archive) == FileAttributes.Archive)
            && ((fa & FileAttributes.Hidden) == 0)) {
          SetTranscodeActive(file);
          TranscodeFile(file);
          break;
        }
      }
    }

    bool isTranscodeActive() {
      string filename = System.IO.Path.Combine(tbDest.Text, transcodeActiveFile);
      if (System.IO.File.Exists(filename))
        return true;
      else
        return false;
    }

    /// <summary>
    /// Sets a monitor file that says a transcode is in progress. No new transcoding will
    /// happen if this file exists. To clear the monitor file
    /// and enable transcoding, call with an empty parameter. 
    /// </summary>
    /// <param name="FileBeingTranscoded">Name of the file being transcoded. 
    /// Blank to clear and enable new transcode operations.</param>
    private void SetTranscodeActive(string FileBeingTranscoded) {
      string statusFile = Path.Combine(tbDest.Text, transcodeActiveFile);
      if (FileBeingTranscoded != "") {
        System.IO.StreamWriter fs = new StreamWriter(statusFile);
        fs.WriteLine(getDestFilename(FileBeingTranscoded));
        fs.Close();
      }
      else
        File.Delete(statusFile);
    }

    string getDestFilename(string SourceFileName) {
      string dest;
      dest = System.IO.Path.GetFileName(SourceFileName);
      dest = System.IO.Path.ChangeExtension(dest, ".mp4");
      dest = System.IO.Path.Combine(tbDest.Text, dest);
      return dest;
    }

    public void TranscodeFile(string FileName) {
      tbLog.AppendText("Trancoding " + FileName + "...");

      string dest = getDestFilename(FileName);

      System.Diagnostics.Process proc = new System.Diagnostics.Process();
      proc.EnableRaisingEvents = false;
      proc.StartInfo.FileName = "transcode.bat";
      proc.StartInfo.Arguments = "\"" + FileName + "\" \"" + dest + "\" \"" + Path.Combine(tbDest.Text, transcodeActiveFile);
      proc.Start();
      try {
        proc.PriorityClass = System.Diagnostics.ProcessPriorityClass.Idle;
      }
      catch (Exception ex) {
        System.Diagnostics.Debug.WriteLine(ex.Message);
      }
    }

    private void checkBox1_CheckedChanged(object sender, EventArgs e) {

    }

  }
}
